package org.example.ws;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Map;

import static org.example.ws.StringConstants.*;

public abstract class AbsChatSessionInterceptor implements HandshakeInterceptor {
    /**
     * 连接握手前验证有没有传递房间参数以及当前用户是否登录
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        Object room = this.getRoom(request);
        Assert.notNull(room, "Room must not be null");
        Object user = this.getUser(request);
        Assert.notNull(user, "User must not be null");
        attributes.put(ROOM_KEY, room);
        attributes.put(USER_KEY, user);
        return this.beforeHandshakeInternal(request, response, wsHandler, Collections.unmodifiableMap(attributes));
    }

    /**
     * 获取房间参数，不能为null
     *
     * @param request
     * @return
     */
    protected Object getRoom(ServerHttpRequest request) {
        return this.toHttp(request).getParameter(ROOM_KEY);
    }

    /**
     * 获取当前用户，不能为null。即便有匿名登录的需求，也应该系统默认生成一个匿名用户，而不是返回null
     *
     * @param request
     * @return
     */
    protected abstract Object getUser(ServerHttpRequest request);

    /**
     * 将请求转换为HttpServletRequest
     *
     * @param request
     * @return
     */
    protected HttpServletRequest toHttp(ServerHttpRequest request) {
        return ((ServletServerHttpRequest) request).getServletRequest();
    }

    /**
     * 根据业务进一步验证是否允许握手，如果没有的话返回true就行了
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    protected abstract boolean beforeHandshakeInternal(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception;

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        this.afterHandshakeInternal();
    }

    protected abstract void afterHandshakeInternal();
}
